﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using SecuritiesAnalysis.Common;
using SecuritiesAnalysis.Interface;
using SecuritiesAnalysis.CurrentData;

namespace SecuritiesAnalysis
{
    public class EXMPACalculator : ICalculator
    {

        private SecuritiesAnalysisDataContext ctx;
        private List<T_HistoryPrice> historyList;
        private List<T_Info_EXPMA> EXMPAList;
        private List<T_StockCode> CodeList;
        private DateTime latest;
        private T_Info_EXPMA expmamod;

        private const decimal param015 = (decimal)(0.15);
        private const decimal param004 = (decimal)(0.04);

        #region ICalculator Members for ALL operation, copy from MACalculator

        public bool Clear()
        {
            ctx.ExecuteCommand("TRUNCATE TABLE T_Info_EXPMA");
            return true;
        }

        public bool ReCalculate()
        {
            Clear();

            CodeList = ctx.T_StockCodes.Where(c => c.Enabled == true).ToList();

            foreach (T_StockCode code in CodeList)
            {
                if (!ReCalculate(code.StockCode))
                {
                    return false;
                }
            }

            return true;
        }

        public bool Calculate()
        {
            CodeList = ctx.T_StockCodes.Where(c => c.Enabled == true).ToList();

            foreach (T_StockCode code in CodeList)
            {
                if (!Calculate(code.StockCode))
                {
                    return false;
                }
            }

            return true;
        }

        public bool CalculateToday()
        {
            CodeList = ctx.T_StockCodes.Where(c => c.Enabled == true).ToList();

            #region 判断是否数据库中有最新记录，如果没有则重新添加，希望能够提高效率
            latest = GetLatestHistoryDate(CodeList[1].StockCode);

            if (latest < DateTime.Today)
            {
                //获取并插入最新记录
                using (DataSpider ds = new DataSpider())
                {
                    ds.UpdateCurrentPrice();
                }
            }
            #endregion

            foreach (T_StockCode code in CodeList)
            {
                if (!CalculateToday(code.StockCode))
                {
                    return false;
                }
            }

            return true;
        }

        #endregion

        public EXMPACalculator()
        {
            ctx = new SecuritiesAnalysisDataContext();
        }

        #region ICalculator Members

        public bool Clear(int stockcode)
        {
            try
            {
                ctx.ExecuteCommand("DELETE FROM T_Info_EXPMA WHERE [STOCKCODE]=" + stockcode);

                return true;
            }
            catch (Exception e)
            {
                Log.OutputError(e.Message);
                return false;
            }
        }

        public bool ReCalculate(int stockcode)
        {
            Clear(stockcode);

            try
            {
                historyList = ctx.T_HistoryPrices.Where(c => c.StockCode == stockcode).OrderBy(c => c.Date).ToList();//按日期升序
                EXMPAList = new List<T_Info_EXPMA>();

                //第0天没有数据
                T_Info_EXPMA mod1 = new T_Info_EXPMA();
                mod1.StockCode = stockcode;
                mod1.Date = historyList[0].Date;
                mod1.EXPMA1 = 0;
                mod1.EXPMA2 = 0;
                EXMPAList.Add(mod1);
                //计算第一天XP为前一天收盘价
                T_Info_EXPMA mod2 = new T_Info_EXPMA();
                mod2.StockCode = stockcode;
                mod2.Date = historyList[1].Date;
                mod2.EXPMA1 = (historyList[1].ClosingPrice.Value - historyList[0].ClosingPrice.Value) * param015 + historyList[0].ClosingPrice.Value;
                mod2.EXPMA2 = (historyList[1].ClosingPrice.Value - historyList[0].ClosingPrice.Value) * param004 + historyList[0].ClosingPrice.Value; ;
                EXMPAList.Add(mod2);

                //计算第二天及以后的
                for (int i = 2; i < historyList.Count; i++)
                {
                    T_Info_EXPMA mod = new T_Info_EXPMA();
                    mod.StockCode = stockcode;
                    mod.Date = historyList[i].Date;

                    mod.EXPMA1 = (historyList[i].ClosingPrice.Value - EXMPAList[i - 1].EXPMA1) * param015 + EXMPAList[i - 1].EXPMA1;
                    mod.EXPMA2 = (historyList[i].ClosingPrice.Value - EXMPAList[i - 1].EXPMA2) * param004 + EXMPAList[i - 1].EXPMA2;

                    EXMPAList.Add(mod);
                }

                ctx.T_Info_EXPMAs.InsertAllOnSubmit(EXMPAList);
                ctx.SubmitChanges();

                return true;
            }
            catch (Exception e)
            {
                Log.OutputError(e.Message);
                return false;
            }
        }

        public bool Calculate(int stockcode)
        {
            try
            {
                latest = GetLatestDate(stockcode);

                historyList = ctx.T_HistoryPrices.Where(c => c.StockCode == stockcode).OrderBy(c => c.Date).ToList();//按日期升序
                EXMPAList = new List<T_Info_EXPMA>();

                //如果当前表中的数据少于2条，则清空重新添加
                if (ctx.T_Info_EXPMAs.Where(e=>e.StockCode==stockcode).Count() < 2)
                {
                    this.Clear(stockcode);

                    //第0天没有数据
                    T_Info_EXPMA mod1 = new T_Info_EXPMA();
                    mod1.StockCode = stockcode;
                    mod1.Date = historyList[0].Date;
                    mod1.EXPMA1 = 0;
                    mod1.EXPMA2 = 0;
                    EXMPAList.Add(mod1);
                    //计算第一天XP为前一天收盘价
                    T_Info_EXPMA mod2 = new T_Info_EXPMA();
                    mod2.StockCode = stockcode;
                    mod2.Date = historyList[1].Date;
                    mod2.EXPMA1 = (historyList[1].ClosingPrice.Value - historyList[0].ClosingPrice.Value) * param015 + historyList[0].ClosingPrice.Value;
                    mod2.EXPMA2 = (historyList[1].ClosingPrice.Value - historyList[0].ClosingPrice.Value) * param004 + historyList[0].ClosingPrice.Value; ;
                    EXMPAList.Add(mod2);
                }

                for (int i = 2; i < historyList.Count; i++)
                {
                    if (historyList[i].Date <= latest)
                    {
                        //过滤已经计算过的日期
                        continue;
                    }

                    T_Info_EXPMA mod = new T_Info_EXPMA();
                    mod.StockCode = stockcode;
                    mod.Date = historyList[i].Date;

                    mod.EXPMA1 = (historyList[i].ClosingPrice.Value - EXMPAList[i - 1].EXPMA1) * param015 + EXMPAList[i - 1].EXPMA1;
                    mod.EXPMA2 = (historyList[i].ClosingPrice.Value - EXMPAList[i - 1].EXPMA2) * param004 + EXMPAList[i - 1].EXPMA2;

                    EXMPAList.Add(mod);
                }

                ctx.T_Info_EXPMAs.InsertAllOnSubmit(EXMPAList);
                ctx.SubmitChanges();

                return true;
            }
            catch (Exception e)
            {
                Log.OutputError(e.Message);
                return false;
            }
        }

        public bool CalculateToday(int stockcode)
        {
            try
            {
                latest = GetLatestHistoryDate(stockcode);

                if (latest < DateTime.Today)
                {
                    //获取并插入最新记录
                    using (DataSpider ds = new DataSpider())
                    {
                        ds.UpdateCurrentPrice(stockcode);
                    }
                }

                historyList = ctx.T_HistoryPrices.Where(c => c.StockCode == stockcode).OrderBy(c => c.Date).ToList();//按日期升序
                expmamod = ctx.T_Info_EXPMAs.Where(o => o.StockCode == stockcode && o.Date == DateTime.Today).FirstOrDefault();

                if (expmamod == null)
                {
                    //如果不存在则插入
                    T_Info_EXPMA mod = new T_Info_EXPMA();
                    mod.StockCode = stockcode;
                    mod.Date = historyList[historyList.Count - 1].Date;

                    mod.EXPMA1 = (historyList.Last().ClosingPrice.Value - EXMPAList.Last().EXPMA1) * param015 + EXMPAList.Last().EXPMA1;
                    mod.EXPMA2 = (historyList.Last().ClosingPrice.Value - EXMPAList.Last().EXPMA2) * param004 + EXMPAList.Last().EXPMA2;

                    ctx.T_Info_EXPMAs.InsertOnSubmit(mod);
                }
                else
                {
                    //如果已存在则更新
                    expmamod.EXPMA1 = (historyList[EXMPAList.Count - 2].ClosingPrice.Value - EXMPAList[EXMPAList.Count - 2].EXPMA1) * param015 + EXMPAList[EXMPAList.Count - 2].EXPMA1;
                    expmamod.EXPMA2 = (historyList[EXMPAList.Count - 2].ClosingPrice.Value - EXMPAList[EXMPAList.Count - 2].EXPMA2) * param004 + EXMPAList[EXMPAList.Count - 2].EXPMA2;
                }

                ctx.SubmitChanges();

                return true;
            }
            catch (Exception e)
            {
                Log.OutputError(e.Message);
                return false;
            }
        }

        #endregion

        #region private methods

        /// <summary>
        /// 获取当前某股票最新历史数据
        /// </summary>
        /// <param name="stockcode">股票代码</param>
        /// <returns>最新历史数据</returns>
        private DateTime GetLatestHistoryDate(int stockcode)
        {
            try
            {
                T_HistoryPrice latest = ctx.T_HistoryPrices.Where(o => o.StockCode == stockcode).OrderByDescending(o => o.Date).First();
                return latest.Date;
            }
            catch (Exception e)
            {
                if (e.Message == "Sequence contains no elements")
                {
                    return DateTime.MinValue;
                }
                return DateTime.MinValue;
            }
        }

        /// <summary>
        /// 获取当前某股票已经计算的最新MA日期
        /// </summary>
        /// <param name="stockcode">股票代码</param>
        /// <returns>最新日期</returns>
        private DateTime GetLatestDate(int stockcode)
        {
            try
            {
                T_Info_EXPMA latest = ctx.T_Info_EXPMAs.Where(o => o.StockCode == stockcode).OrderByDescending(o => o.Date).First();
                return latest.Date;
            }
            catch (Exception e)
            {
                if (e.Message == "Sequence contains no elements")
                {
                    return DateTime.MinValue;
                }
                return DateTime.MinValue;
            }
        }

        #endregion
    }
}
